package com.example.ftp.Dao.Impl;

import com.example.ftp.Beans.Document;
import com.example.ftp.Beans.Ftp;
import com.example.ftp.Dao.FtpDao;
import com.example.ftp.Util.FtpUtil;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import static com.example.ftp.Util.FtpUtil.*;

/**
 * @program: FTP
 * @description:
 * @author: LOTP
 * @create: 2022-01-07 15:54
 **/
public class FtpDaoImpl implements FtpDao {

    private final static Logger logger = LoggerFactory.getLogger(FtpDaoImpl.class);

    private  FTPClient ftpClient = null;

    public FTPClient getFtpClient() {
        return ftpClient;
    }

    public FtpDaoImpl(Ftp ftp){
        //初始化ftp客户端
        ftpClient = FtpUtil.getFTPClient(ftp.getHost(),ftp.getPort(),ftp.getUserName(),ftp.getPassword());
    }

    /**
     * 传入服务端从根目录开始的完整文件路径，改变当前服务端工作目录
     */
    public boolean changeWorkingDirectory(String ftpPath) {
        try {
            while (!getWorkingDirectory().equals("/")) {
                ftpClient.changeToParentDirectory();
            }

            return ftpClient.changeWorkingDirectory(clientCharsetToServer(ftpPath));
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public FTPFile[] listFiles(String ftpPath){
        if (ftpClient == null){
            return null;
        }
        try {
            //ftpClient.changeWorkingDirectory(ftpPath);//获取所有的目录
            changeWorkingDirectory(ftpPath);
            return ftpClient.listFiles();//返回获取到的目录信息
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    @Override
    public List<Document> getWorkingDirectoryDocuments() {
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            SimpleDateFormat df = new SimpleDateFormat("yyyyMMddhhmmss");
            FTPFile[] ftpFiles = ftpClient.listFiles();
            List<Document> documents = new ArrayList<Document>(ftpFiles.length);

            for (FTPFile ftpFile : ftpFiles) {
                //document.setName(serverCharsetToClient(ftpFile.getName()));
                Document document = new Document();
                document.setName(ftpFile.getName());
                document.setType(ftpFile.getType());
                document.setSize(ftpFile.getSize());

                String createdTime = simpleDateFormat.format(ftpFile.getTimestamp().getTime());
                document.setCreatedTime(createdTime);

                String updatedTime = ftpClient.getModificationTime(ftpFile.getName());
                if (updatedTime != null){

                    updatedTime = updatedTime.substring(updatedTime.indexOf(" ") + 1);
                    updatedTime = simpleDateFormat.format(df.parse(updatedTime));
                }else {
                    updatedTime = createdTime;
                }

                document.setUpdatedTime(updatedTime);
                //System.out.println(simpleDateFormat.format(df.parse(ftpClient.getModificationTime(ftpFile.getName()))));

                document.setPath(getWorkingDirectory());
                documents.add(document);

            }

            return documents;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    @Override
    public FTPFile getFTPFile(String ftpPath) {
        String serverFileName = ftpPath;
        if (serverFileName.indexOf("/") != -1) {
            String[] pathItem = serverFileName.split("/");
            serverFileName = pathItem[pathItem.length - 1];
        }

        String serverDirectory = serverCharsetToClient(ftpPath.substring(0, ftpPath.length() - ("/" + serverFileName).length()));

        if (changeWorkingDirectory(serverDirectory)) {
            try {
                for (FTPFile ftpFile : ftpClient.listFiles()) {
                    if (ftpFile.getName().equals(serverFileName)) {
                        return ftpFile;
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("服务端工作目录：" + serverDirectory + "不存在");
        }

        return null;
    }





    /**
     * 当前工作目录下是否有查询的文件
     * @param fileName
     * @return
     */
    public boolean isWorkingDirectoryHasFile(String fileName) {
        try {
            FTPFile[] ftpFiles = ftpClient.listFiles();
            for (FTPFile ftpFile : ftpFiles) {
                if (ftpFile.getName().equals(fileName)) {
                    return true;
                }
            }
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }




    /**
     * 下载FTP文件，本地文件已存在则覆盖
     *
     * @param ftpPath 服务器路径
     * @param localPath 本地路径
     */
    @Override
    public boolean downloadFile(String ftpPath, String localPath) {

        ftpPath = FtpUtil.clientCharsetToServer(ftpPath);
        System.out.println("------------------下载文件--------------------");
        File clientDirectory = new File(localPath);
        // 如果文件夹路径不存在，则创建文件夹
        if (!clientDirectory.exists()) {
            System.out.print("客户端目录：" + localPath + "不存在，");
            if (clientDirectory.mkdirs()) {
                System.out.print("已创建");
            } else {
                System.out.print("创建失败\n");
                return false;
            }

            System.out.print("\n");
        }

        FTPFile ftpFile = getFTPFile(ftpPath);
        System.out.println("当前服务端工作目录：" + getWorkingDirectory());
        if (ftpFile == null) {
            System.out.println("服务端工作目录：" + serverCharsetToClient(ftpPath) + "不存在");
            return false;
        }

        String clientFilePath = localPath + "/" + serverCharsetToClient(ftpFile.getName());
        File clientFile = new File(clientFilePath);

        if (ftpFile.isFile()) {
            // 判断文件是否存在，存在则删除重新下载
            if (clientFile.exists()) {
                System.out.print("文件" + clientFilePath + "已存在，");
                if (clientFile.delete()) {
                    System.out.print("已删除");
                } else {
                    System.out.print("删除失败\n");
                    return false;
                }

                System.out.print("\n");
            }

            try {
                OutputStream outputStream = new FileOutputStream(clientFilePath);
                // 将服务端当前目录下ftpFile.getName()名称的文件输出到本地路径clientFilePath下
                boolean isSuccess = ftpClient.retrieveFile(ftpFile.getName(), outputStream);
                outputStream.flush();
                outputStream.close();
                System.out.println("下载文件：" + clientFilePath + "，" + (isSuccess ? "成功" : "失败"));
                return isSuccess;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        } else {
            if (clientFile.exists()) {
                System.out.println("文件夹" + clientFilePath + "已存在，");
            } else {
                if (clientFile.mkdirs()) {
                    System.out.println("客户端目录：" + clientFilePath + "已建立");
                } else {
                    System.out.println("客户端目录：" + clientFilePath + "建立失败");
                    return false;
                }
            }

            try {
                System.out.println("进入服务端工作目录：" + serverCharsetToClient(ftpFile.getName()));
                if (!ftpClient.changeWorkingDirectory(ftpFile.getName())) {
                    System.out.println("，失败");
                    return false;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                for (FTPFile ftpFile1 : ftpClient.listFiles()) {
                    downloadFile(serverCharsetToClient(ftpPath + "/" + ftpFile1.getName()), clientFilePath);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            return true;
        }

    }

    @Override
    public boolean changeToParentDirectory() {

        try {
            if (ftpClient.changeToParentDirectory()){
                logger.info("返回上一级目录成功");
                return true;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }


    @Override
    public boolean upload(String ftpPath, String localPath, boolean isCoverDirectory, boolean isCoverFile) throws Exception {
        System.out.println("------------------上传文件--------------------");
        if (ftpPath != null) {
            if (!this.changeWorkingDirectory(ftpPath)) {
                System.out.println("服务端路径错误");
                return false;
            }
        }

        System.out.println("当前服务端工作目录：" + getWorkingDirectory());
        File file = new File(localPath);
        // 防止中文目录创建失败或者中文名的文件上传失败
        String currentFileName = FtpUtil.clientCharsetToServer(file.getName());
        if (file.isDirectory()) {
            if (isWorkingDirectoryHasFile(currentFileName)) {
                System.out.print("服务端工作目录" + file.getName() + "已存在" + "，");
                if (isCoverDirectory) {
                    if (ftpClient.deleteFile(currentFileName)) {
                        System.out.print("已删除");
                        // 在服务端当前目录创建名称为currentFileName的文件夹
                        if (ftpClient.makeDirectory(currentFileName)) {
                            System.out.print("已重建");
                        } else {
                            System.out.print("重建失败");
                        }
                    } else {
                        System.out.print("删除失败\n");
                        return false;
                    }
                } else {
                    System.out.print("保持不变");
                }

                System.out.print("\n");
            } else {
                System.out.print("服务端工作目录" + file.getName() + "不存在，");
                // 在服务端当前目录创建名称为currentFileName的文件夹
                if (ftpClient.makeDirectory(currentFileName)) {
                    System.out.print("已创建");
                } else {
                    System.out.print("创建失败");
                }

                System.out.print("\n");
            }

            String[] fileNames = file.list();
            if (fileNames == null || fileNames.length == 0) {
                return true;
            }

            if (ftpClient.changeWorkingDirectory(currentFileName)) {
                System.out.println("进入服务端工作目录" + file.getName());
            }

            for (String fileName : fileNames) {
                upload(null, file.getPath() + "/" + fileName, isCoverDirectory, isCoverFile);
            }

            if (!ftpClient.changeToParentDirectory()) {
                System.out.println("返回上一级目录失败");
            }
        } else {
            if (isWorkingDirectoryHasFile(currentFileName)) {
                System.out.print("当前服务端工作目录下存在文件：" + file.getName() + "，");
                if (isCoverFile) {
                    FileInputStream fileInputStream = new FileInputStream(file);
                    // 在服务端当前目录创建名称为currentFileName，文件流为fileInputStream，对应路径filePath的文件
                    if (ftpClient.storeFile(currentFileName, fileInputStream)) {
                        System.out.print("已覆盖");
                    } else {
                        System.out.print("覆盖失败");
                    }

                    fileInputStream.close();
                } else {
                    System.out.print("不覆盖");
                }
            } else {
                System.out.print("当前服务端工作目录下不存在文件：" + file.getName() + "，");
                FileInputStream fileInputStream = new FileInputStream(file);
                // 在服务端当前目录创建名称为currentFileName，文件流为fileInputStream，对应路径filePath的文件
                if (ftpClient.storeFile(currentFileName, fileInputStream)) {
                    System.out.print("已存储");
                } else {
                    System.out.print("存储失败");
                }

                fileInputStream.close();
            }

            System.out.print("\n");
        }

        return true;
    }


    @Override
    public boolean deleteFile(String filePath) {
        boolean flag = false;

        try {

            //对中文名称进行转码
            filePath = clientCharsetToServer(filePath);
            ftpClient.deleteFile(filePath);
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }


    @Override
    public boolean deleteDirectory(String directoryPath) throws IOException {
        boolean res= false;
        FTPFile[] files= listFiles(directoryPath);//获取文件数组
        for (int i = 0; i <files.length ; i++) {
            if (files[i].isDirectory()){ //如果是删除目录
                deleteDirectory(directoryPath+"/"+files[i].getName());//删除目录
            }else {
                ftpClient.deleteFile(directoryPath+"/"+files[i].getName());//删除文件
            }

        }
        return ftpClient.removeDirectory(directoryPath);
    }



    @Override
    public boolean makeDirectory(String ftpPath) throws IOException {
        boolean res = false;

        if (null == ftpClient){
            return res;
        }

        String[] item = ftpPath.split("/");//以‘/’分割成字符串数组
        String currentPath="";
        for (int i = 0; i <item.length-1 ; i++) {

            currentPath = currentPath +"/"+item[i];//创建目录
            ftpClient.makeDirectory(currentPath);
        }
        return ftpClient.makeDirectory(ftpPath);
    }




    @Override
    public boolean replaceName(String oldPath, String newPath) throws IOException {

        if (null == ftpClient){
            return false;
        }
        return ftpClient.rename(oldPath,newPath);
    }

    @Override
    public void setHiddenDocument(boolean flag){
        ftpClient.setListHiddenFiles(flag);
    }




}


